/*
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
 *      
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *      
 *      You should have received a copy of the GNU General Public License
 *      along with this program; if not, write to the Free Software
 *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *      MA 02110-1301, USA.
 */

package bgtp;

import java.util.*;
import java.lang.*;
import java.io.IOException;
import java.lang.Thread;
import common.*;

/**
 *класс занимется обслуживанием соединеия с абонентом либо с севером
 *ссодержит основную логику протокола в плане запросов подтверждений
 */
public class BGTPWorker extends Thread
{
    private String			iam;
    private OverHTTP			channel;
    private TreeMap<String, String>	request;
    private TreeMap<String, String>	response;
    private BGTPmm			mmodule;
    private BGTPLog			logger;
    private boolean			nowDie;

    private Vector<TreeMap<String, String>> outEvents;

    /**
     *конструяктор
     *@param chanel_ HTTP канал передачи
     *@param mm экземпляр основного модуля. нужен для диспетчеризацции сообщений
     *@param guid_ идентификатор абонента
     */
    public BGTPWorker(OverHTTP channel_, BGTPmm mm, String guid_)
    {
	outEvents = new Vector<TreeMap<String, String>>();
	mmodule	  = mm;
	channel	  = channel_;
	iam	  = guid_;
	response  = new TreeMap<String, String>();
	logger	  = new BGTPLog("BGTPWorker");
	channel.setBlocking(false);
    }

    /**
     *отановить обслуживание соединеия
     */
    public void shutdown()
    {
	nowDie = true;
    }

    /**
     *отправить сообщение данному абоненту
     *@param ms отправляемое сообщение
     */
    public void postMessage(TreeMap<String, String> ms)
    {
	synchronized(outEvents)
	    {
		outEvents.add(ms);
	    }
    }

    /**
     *проверить пришедший запрос на валидность
     *@param rqst запрос который млкдует проверить
     *@return взвращает результат проверки который одновременно является частью ответа
     */
    private String validate(TreeMap<String, String> rqst)
    {
	if(rqst.containsKey("GUID") == false)
	    {
		logger.error("validate", "Request haven't got GUID. possibly corrupted");
		return "HTTP/1.1 500 No GUID";
	    }

	//пока ограничимся проверкой гуида
	if(rqst.get("GUID").equals(iam) == false)
	    {
		logger.error("validate", "Diferent GUID's");
		return "HTTP/1.1 500 Bad GUID";
	    }

	return "HTTP/1.1 200 OK";
    }

    /**
     *проверить пришедший запрос на наличие обязательных полей
     *@param rqst запрос который млкдует проверить
     *@return взвращает результат проверки
     */
    private boolean hasMandatoryFields(TreeMap<String, String> rqst)
    {
	return rqst.containsKey("GUID") & rqst.containsKey("Action") & rqst.containsKey("ReqType");
    }

    /**
     *проверить пришедший запрос на то ответ ли это
     *@param rqst запрос который млкдует проверить
     *@return взвращает результат проверки
     */
    private boolean isResponse(TreeMap<String, String> rqst)
    {
	String rqt = request.get("ReqType");
	if(rqt.startsWith("HTTP") == true)
	    {
		return true;
	    }
	return false;
    }

    public void run()
    {
	//непосредственно реализация логики протокола
	//кроме регистрации/аутентиикации
	//на самао деле вся логика это верификация + хартбиты
	Vector<TreeMap<String, String>>	tmpOut;
	TreeMap<String, String> request_;

	String			responString = "";
	final int		ST_RECV	     = 0;
	final int		ST_SEND	     = 1;
	final int		ST_ERROR     = 3;
	final int		ST_HANDL     = 4;
	int			state	     = ST_RECV;
	boolean			nowDie	     = false;

	logger.info("run", "Worker "+iam+" sarted");
	while(nowDie == false)
	    {
		switch(state)
		    {
		    case ST_RECV:
			//logger.info("run", "ST_RECV");
			try
			    {
				request = channel.recv();
			    }
			catch(IOException ioe)
			    {
				logger.info("run{ST_RECV}", "Connection break");
				state = ST_ERROR;
				break;
			    }

			if(null == request)
			    {
				state = ST_SEND;
				break;
			    }

			if(hasMandatoryFields(request) == true)
			    {
				state = ST_HANDL;
				break;
			    }
			else
			    {
				state = ST_ERROR;
				break;
			    }
			//break;

		    case ST_HANDL:
			//logger.info("run", "ST_HANDL");
			if(isResponse(request) == true)
			    {
				//это подтверждение
				//logger.info("run", "request confirmed");
				state = ST_SEND;
				break;
			    }
			else
			    {
				//здесь проверить на хартбиты
				response = new TreeMap<String, String>();
				response.put("ReqType", validate(request));
				response.put("GUID", iam);
				response.put("Action", "Accepted");
				response.put("Body", "");
				outEvents.insertElementAt(response, 0);
				mmodule.mail(request);
				state = ST_SEND;
				break;
			    }
			//break;

		    case ST_SEND:
			//logger.info("run", "ST_SEND");
			try
			    {
				if(outEvents.size() > 0)
				    {
					synchronized(outEvents)
					    {
						tmpOut	  = outEvents;
						outEvents = new Vector<TreeMap<String, String>>();
					    }
					
					for(TreeMap<String, String> item: tmpOut)
					    {
						channel.send(item);
					    }
				    }
				else
				    {
					//работы нет можно спать
					Helper.sleep(100);
				    }
			    }
			catch(IOException ioe)
			    {
				logger.info("run{ST_SEND}", "Connection break");
				state = ST_ERROR;
				break;	
			    }
			state = ST_RECV;
			break;

		    case ST_ERROR:
			logger.error("run", "Shit happens");
			nowDie = true;
			break;
		    }
	    }
	logger.info("run", "Worker "+iam+" finished");
	channel.close();
    }
}